package com.bjut.vendormgrsys.service.impl;

import com.bjut.vendormgrsys.constant.Constant;
import com.bjut.vendormgrsys.constant.Constant.PositionStatus;
import com.bjut.vendormgrsys.constant.Constant.ResumeStatus;
import com.bjut.vendormgrsys.model.domain.PositionPO;
import com.bjut.vendormgrsys.model.domain.ResumePO;
import com.bjut.vendormgrsys.model.repository.PositionRepository;
import com.bjut.vendormgrsys.model.repository.ResumeRepository;
import com.bjut.vendormgrsys.service.PositionService;
import com.bjut.vendormgrsys.support.bo.RoleBO;
import com.bjut.vendormgrsys.support.bo.UserBO;
import com.bjut.vendormgrsys.util.DateUtils;
import com.bjut.vendormgrsys.util.DateUtils.Pattern;
import com.bjut.vendormgrsys.util.JsonUtils;
import com.bjut.vendormgrsys.web.dto.other.Body5;
import com.bjut.vendormgrsys.web.dto.other.Degree;
import com.bjut.vendormgrsys.web.dto.other.JobType;
import com.bjut.vendormgrsys.web.dto.other.PositionInfo;
import com.bjut.vendormgrsys.web.dto.other.PositionSearch;
import com.bjut.vendormgrsys.web.dto.other.PositionSearchQueryFilter;
import com.bjut.vendormgrsys.web.dto.other.PositionSearchQueryFilterDatePublished;
import com.bjut.vendormgrsys.web.dto.other.Salary;
import com.bjut.vendormgrsys.web.dto.Status;
import com.bjut.vendormgrsys.web.dto.other.WeChatPositionType;
import com.bjut.vendormgrsys.web.dto.other.WorkYears;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class PositionServiceImpl implements PositionService {

    @PersistenceContext
    private EntityManager entityManager;

    private final PositionRepository repository;

    private final ResumeRepository resumeRepository;

    @Autowired
    public PositionServiceImpl(PositionRepository repository, ResumeRepository resumeRepository) {
        this.repository = repository;
        this.resumeRepository = resumeRepository;
    }

    @Override
    @Transactional
    public void savePositionPO(PositionInfo positionInfo, UserBO creator) {
        boolean isPersist = true;
        String id = positionInfo.getId();
        PositionPO positionPO = null;
        if (StringUtils.hasLength(id)) {
            Optional<PositionPO> byId = repository.findById(id);
            if (byId.isPresent()) {
                positionPO = byId.get();
                isPersist = false;
            }
        }
        if (positionPO == null) {
            positionPO = new PositionPO();
            positionInfo.setId(null);
        }
        BeanUtils.copyProperties(positionInfo, positionPO,
                "vendorRecommendCount", "status", "datePublished", "lastUpdated", "principal", "uid");
        positionPO.setDegree(JsonUtils.toString(positionInfo.getDegree()));
        positionPO.setJobType(JsonUtils.toString(positionInfo.getType()));
        positionPO.setSalary(JsonUtils.toString(positionInfo.getSalary()));
        positionPO.setWeChatPositionType(JsonUtils.toString(positionInfo.getWeChatPositionType()));
        positionPO.setWorkYears(JsonUtils.toString(positionInfo.getWorkYears()));
        positionPO.setWorkAddress(positionInfo.getLocation());
        positionPO.setLastUpdated(DateUtils.now());
        positionPO.setEnterpriseName(creator.getCompany());
        if (!isPersist) {
            entityManager.merge(positionPO);
        } else {
            positionPO.setUid(creator.getId());
            positionPO.setPrincipal(creator.getAccount());
            positionPO.setStatus(PositionStatus.PUBLISHING.getKey());
            positionPO.setDatePublished(DateUtils.now());
            entityManager.persist(positionPO);
        }
    }

    @Override
    public PositionInfo findById(String positionId, UserBO principal) {
        if (!StringUtils.hasLength(positionId)) {
            throw new RuntimeException("职位信息不存在：" + positionId);
        }
        PositionPO positionPO;
        List<RoleBO> role = principal.getRole();
        String roleName = role.get(0).getName();
        if (Constant.RoleEnum.ROLE_VENDOR.getKey().equals(roleName) ||
                Constant.RoleEnum.ROLE_ADMIN.getKey().equals(roleName)) {
            // 可以查所有职位
            positionPO = repository.findById(positionId).orElse(null);
        } else if (Constant.RoleEnum.ROLE_HRBP.getKey().equals(roleName)) {
            // 只能查自己创建的职位
            positionPO = repository.getByIdAndUid(positionId, principal.getId());
        } else {
            throw new RuntimeException("无权限查看职位列表");
        }
        if (positionPO == null) {
            throw new RuntimeException("职位信息不存在！");
        }
        return getPositionInfo(positionPO);
    }

    private PositionInfo getPositionInfo(PositionPO positionPO) {
        PositionInfo positionInfo = new PositionInfo();
        BeanUtils.copyProperties(positionPO, positionInfo);
        String date = DateUtils.formatDate(positionPO.getDatePublished(), Pattern.PATTERN_DEFAULT);
        positionInfo.setStartDate(date);
        positionInfo.setDateCreated(date);
        positionInfo.setDegree(JsonUtils.toBean(positionPO.getDegree(), Degree.class));
        positionInfo.setType(JsonUtils.toBean(positionPO.getJobType(), JobType.class));
        positionInfo.setSalary(JsonUtils.toBean(positionPO.getSalary(), Salary.class));
        positionInfo.setWeChatPositionType(JsonUtils.toBean(positionPO.getWeChatPositionType(), WeChatPositionType.class));
        positionInfo.setWorkYears(JsonUtils.toBean(positionPO.getWorkYears(), WorkYears.class));
        positionInfo.setLocation(positionPO.getWorkAddress());
        return positionInfo;
    }

    @Override
    public long findAll(final PositionSearch body, List<PositionInfo> items, UserBO principal) {
        Pageable pageable = Constant.getPageable(body.getOffset(), body.getMax());
        List<RoleBO> role = principal.getRole();
        String roleName = role.get(0).getName();
        String creator;
        if (Constant.RoleEnum.ROLE_VENDOR.getKey().equals(roleName)) {
            // 可以查所有职位
            creator = null;
        } else if (Constant.RoleEnum.ROLE_ADMIN.getKey().equals(roleName)) {
            // 可以查所有职位
            creator = null;
        } else if (Constant.RoleEnum.ROLE_HRBP.getKey().equals(roleName)) {
            // 只能查自己创建的职位
            creator = principal.getId();
        } else {
            throw new RuntimeException("无权限查看职位列表");
        }
        Specification<PositionPO> specification = (Specification<PositionPO>) (root, query, builder) -> {
            List<Predicate> predicates = new ArrayList<>();
            PositionSearchQueryFilter queryFilter = body.getQueryFilter();
            if (StringUtils.hasLength(creator)) {
                predicates.add(builder.equal(root.get("uid").as(String.class), creator));
            }
            if (queryFilter != null) {
                String positionName = queryFilter.getPositionName();
                if (StringUtils.hasLength(positionName)) {
                    predicates.add(builder.like(root.get("name").as(String.class), "%" + positionName + "%"));
                }
                String enterpriseName = queryFilter.getEnterpriseName();
                if (StringUtils.hasLength(enterpriseName)) {
                    predicates.add(builder.like(root.get("enterpriseName").as(String.class), "%" + enterpriseName + "%"));
                }
                String jobType = queryFilter.getJobType();
                if (StringUtils.hasLength(jobType)) {
                    predicates.add(builder.equal(root.get("jobType").as(String.class), jobType));
                }
                String status = queryFilter.getStatus();
                if (StringUtils.hasLength(status)) {
                    predicates.add(builder.equal(root.get("status").as(String.class), status));
                }
                PositionSearchQueryFilterDatePublished datePublished = queryFilter.getDatePublished();
                if (datePublished != null) {
                    Long from = Long.parseLong(datePublished.getFrom());
                    Long to = Long.parseLong(datePublished.getTo());
                    predicates.add(builder.between(root.get("datePublished").as(Long.class), from, to));
                }
            }
            return builder.and(predicates.toArray(new Predicate[0]));
        };
        Page<PositionPO> pageAll = repository.findAll(specification, pageable);
        for (PositionPO positionPO : pageAll.getContent()) {
            items.add(getPositionInfo(positionPO));
        }
        return pageAll.getTotalElements();
    }

    @Override
    public List<Status> findAllStatus(UserBO principal) {
        List<PositionPO> all;
        List<RoleBO> role = principal.getRole();
        String roleName = role.get(0).getName();
        if (Constant.RoleEnum.ROLE_VENDOR.getKey().equals(roleName)) {
            // 可以查所有职位
            all = repository.findAll();
        } else if (Constant.RoleEnum.ROLE_ADMIN.getKey().equals(roleName)) {
            // 可以查所有职位
            all = repository.findAll();
        } else if (Constant.RoleEnum.ROLE_HRBP.getKey().equals(roleName)) {
            // 只能查自己创建的职位
            all = repository.getAllByPrincipalEquals(principal.getAccount());
        } else {
            throw new RuntimeException("无权限查看职位列表");
        }
        Map<String, Long> collect = all.stream().collect(Collectors.groupingBy(PositionPO::getStatus, Collectors.counting()));
        Status[] array = new Status[3];
        int count = 0;
        for (String key : collect.keySet()) {
            int value = collect.get(key).intValue();
            Status status = new Status().key(key).name(Constant.getPositionStatusName(key)).value(value);
            if (PositionStatus.PUBLISHING.getKey().equals(key)) {
                array[1] = status;
            } else if (PositionStatus.REVOKED.getKey().equals(key)) {
                array[2] = status;
            }
            count += value;
        }
        if (!collect.containsKey(PositionStatus.PUBLISHING.getKey())) {
            array[1] = new Status().key(PositionStatus.PUBLISHING.getKey()).name(PositionStatus.PUBLISHING.getName()).value(0);
        }
        if (!collect.containsKey(PositionStatus.REVOKED.getKey())) {
            array[2] = new Status().key(PositionStatus.REVOKED.getKey()).name(PositionStatus.REVOKED.getName()).value(0);
        }
        array[0] = new Status().key(PositionStatus.ALL.getKey()).name(PositionStatus.ALL.getName()).value(count);
        return Arrays.asList(array);
    }

    @Override
    public void validPositionInfo(PositionInfo positionInfo) {
        Assert.notNull(positionInfo.getSalary(), "[薪资待遇]不能为空");
        Assert.notNull(positionInfo.getNumber(), "[招聘人数]不能为空");
        Assert.notNull(positionInfo.getDegree(), "[学历要求]不能为空");
        Assert.notNull(positionInfo.getLocation(), "[工作地点]不能为空");
        Assert.notNull(positionInfo.getName(), "[职位名称]不能为空");
        Assert.notNull(positionInfo.getDetail(), "[详细信息]不能为空");
        Assert.notNull(positionInfo.getType(), "[工作类型]不能为空");
        Assert.notNull(positionInfo.getWeChatPositionType(), "[招聘类型]不能为空");
        Assert.notNull(positionInfo.getWorkYears(), "[工作年限]不能为空");
    }

    @Override
    @Transactional
    public void changeStatus(List<Body5> bodies) {
        for (Body5 body : bodies) {
            String id = body.getId();
            if (!StringUtils.hasLength(id)) {
                throw new RuntimeException("职位ID不能为空！");
            }
            String status = body.getStatus();
            if (!StringUtils.hasLength(status)) {
                throw new RuntimeException("职位状态不能为空！");
            }
            Constant.getPositionStatusName(status);
            Optional<PositionPO> byId = repository.findById(id);
            if (!byId.isPresent()) {
                throw new RuntimeException("职位不存在！");
            }
            if (PositionStatus.REVOKED.getKey().equals(status)) {
                List<ResumePO> allByPositionId = resumeRepository.getAllByPositionId(id);
                for (ResumePO po : allByPositionId) {
                    if (!ResumeStatus.RECOMMENDING.getKey().equals(po.getStatus())) {
                        continue;
                    }
                    po.setStatus(ResumeStatus.REFUSE.getKey());
                    entityManager.merge(po);
                }
            }
            PositionPO positionPO = byId.get();
            positionPO.setStatus(status);
            positionPO.setLastUpdated(DateUtils.now());
            entityManager.merge(positionPO);
        }
        entityManager.flush();
    }
}
